#ifndef _LINKED_LIST_H
#define _LINKED_LIST_H

#include "LinkedListNode.h"

template <typename T>
class LinkedList
{
	
private:
	LinkedListNode<T>* _firstNode;
	LinkedListNode<T>* _lastNode;

public:
	LinkedList() : _firstNode(NULL), _lastNode(NULL) {}

	LinkedList(LinkedList<T>& list) : _firstNode(NULL), _lastNode(NULL)
	{
		printf("copy constructor\n");
		LinkedListNode<T>* n = list.getFirstNode();
		
		while(n != NULL)
		{
			addToTail(n->getItem());
			n = n->getNext();
		}
	}

	LinkedList<T>& operator=(LinkedList <T>& l);

	void addToHead(const T& item)
	{
		LinkedListNode<T>* newNode = new LinkedListNode<T>(item, _firstNode);
		_firstNode = newNode;
		if(_lastNode == NULL)
		{
			_lastNode = _firstNode;
		}
	}

	void addToTail(const T& item)
	{
		LinkedListNode<T>* newNode = new LinkedListNode<T>(item, NULL);

		if(_lastNode == NULL && _firstNode == NULL)
		{
			_lastNode = newNode;
			_firstNode = newNode;
		}
		else
		{
			_lastNode->setNext(newNode);
			_lastNode = newNode;
		}
	}

	const T& removeToHead()
	{
		LinkedListNode<T>* auxNode = _firstNode;
		if(_lastNode != NULL && _firstNode != NULL)
		{
			_firstNode = _firstNode->getNext();
		}
		return auxNode->getItem();
	}

	~LinkedList()
	{
		LinkedListNode<T>* auxNode = _firstNode;
		while(auxNode != NULL)
		{
			LinkedListNode<T>* next = auxNode->getNext();
			delete auxNode;
			auxNode = next;
		}
	}

	LinkedListNode<T>* getFirstNode()
	{
		return _firstNode;
	}

	int size()
	{
		int cont = 0;
		LinkedListNode<T>* auxNode = _firstNode;
		while(auxNode != NULL)
		{
			LinkedListNode<T>* next = auxNode->getNext();
			cont++;
			auxNode = next;
		}
		return cont;
	}
};

template <class T>
LinkedList<T>& LinkedList<T>::operator=(LinkedList <T>& l)
{
	printf("operator =\n");

	LinkedListNode<T>* auxNode = _firstNode;
	
	while(auxNode != NULL)
	{
		LinkedListNode<T>* next = auxNode->getNext();
		delete auxNode;
		auxNode = next;
	}
// 	LinkedList<T>::~LinkedList();
// 	delete this;
	LinkedListNode<T>* n = l.getFirstNode();
	
	while(n != NULL)
	{
		addToTail(n->getItem());
		n = n->getNext();
	}
	return *this;
}

/**
begin of template overlap for T*
*/
template <typename T>
class LinkedList<T*>
{
	
private:
	LinkedListNode<T*>* _firstNode;
	LinkedListNode<T*>* _lastNode;

public:
	LinkedList() : _firstNode(NULL), _lastNode(NULL) {}

	LinkedList(LinkedList<T*>& list) : _firstNode(NULL), _lastNode(NULL)
	{
		printf("copy constructor\n");
		LinkedListNode<T*>* n = list.getFirstNode();
		
		while(n != NULL)
		{
			addToTail(n->getItem());
			n = n->getNext();
		}
	}

	//LinkedList<T>& operator=(LinkedList <T>& l);

	void addToHead(T* item)
	{
		LinkedListNode<T*>* newNode = new LinkedListNode<T*>(item, _firstNode);
		_firstNode = newNode;
		if(_lastNode == NULL)
		{
			_lastNode = _firstNode;
		}
	}

	void addToTail(T* item)
	{
		LinkedListNode<T*>* newNode = new LinkedListNode<T*>(item, NULL);

		if(_lastNode == NULL && _firstNode == NULL)
		{
			_lastNode = newNode;
			_firstNode = newNode;
		}
		else
		{
			_lastNode->setNext(newNode);
			_lastNode = newNode;
		}
	}

	T* removeToHead()
	{
		LinkedListNode<T*>* auxNode = _firstNode;
		if(_lastNode != NULL && _firstNode != NULL)
		{
			_firstNode = _firstNode->getNext();
		}
		return auxNode->getItem();
	}

	~LinkedList()
	{
		LinkedListNode<T*>* auxNode = _firstNode;
		while(auxNode != NULL)
		{
			LinkedListNode<T*>* next = auxNode->getNext();
			delete auxNode->getItem();
			auxNode = next;
		}
	}

	LinkedListNode<T*>* getFirstNode()
	{
		return _firstNode;
	}

	int size()
	{
		int cont = 0;
		LinkedListNode<T*>* auxNode = _firstNode;
		while(auxNode != NULL)
		{
			LinkedListNode<T*>* next = auxNode->getNext();
			cont++;
			auxNode = next;
		}
		return cont;
	}
};
#endif